<?php
/*
hydratag search engine indexer: Keystore
Uses the voswork keystore (cache and files)

Recommneded for relatively small indexes.
TODO: sort by popularity or not?
TODO: sort by length desc --  speeds up search?
*/

class keyStoreIndexer extends indexer
{
	// instance of voswork keystore
	protected $store;

	public function __construct($namespace = null)
	{
		$this->store = new keyStore('index'.$namespace);
	}

	protected function insert($object, array $tags)
	{
		// get a small ID to represent the bulky object
		$key = $this->storeObject($object);

		foreach ($tags as &$tag)
			$this->relate($key,$tag);
	}

	protected function query(array $tags)
	{
		// eliminate copies
		$tags = array_unique($tags);

		// fill the array with some partial matches, to iteratively
		$objectKeys = $this->getKeys( array_pop($tags) );

		foreach ($tags as &$tag)
		{
			if (count($objectKeys) <= 1)
				// one or no results, no need to refine further
				break;
			// look for mutual object keys for next tab
			$objectKeys = array_intersect($objectKeys,$this->getKeys($tag));
		}

		// cut number of search results
		// TODO: comment out when sorting is enabled
		$objectKeys = array_slice($objectKeys,0,self::$max_results);

		// create an array of the orginal objects
		$objects = array();
		foreach ($objectKeys as $key)
			$objects[] = $this->retrieveObject($key);

		//$this->sort($objects);

		return array_slice($objects,0,self::$max_results);
	}

	// sort objects by popularity TODO
	protected function sort(&$objects)
	{
		// callback could use references
		usort($objects,function ($a,$b){});
	}

	public function flush()
	{
		$this->store->flush();
	}

	// store an object returning a key to use to identify it
	protected function storeObject($object)
	{
		$key = md5(serialize($object));
		$this->store->set($key,$object);
		return $key;
	}

	// get an object back given the key
	// TODO: popularity
	protected function retrieveObject($key)
	{
		// TODO: increase hits (likes)
		return $this->store->get($key);
	}

	// relate an object key to a tag
	protected function relate($objectKey,$tag)
	{
		// load the list of objects associated with this tag
		$objectKeys = $this->store->get($tag);

		// create if doesn't already exist
		if (!$objectKeys)
			$objectKeys = array();

		// check to see if relationship already exists
		if (in_array($objectKey,$objectKeys))
			return;
		else
		{
			// add the relationship
			$objectKeys[] = $objectKey;
			// save the updated map
			$this->store->set($tag,$objectKeys);
		}
	}

	// get an array of all objectKeys relating to a tag
	// empty array on no match
	protected function getKeys($tag)
	{
		return (array) $this->store->get($tag);
	}
}
